package allRun;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

/**
 * <P> This class represents a collection of test suites which demonstrate 
 * the functionality of <CODE>Tester</CODE> library. </P>
 * 
 * @author Virag Shah
 * @since 22 March 2011
 * 
 */
public class ExamplesAllRun {
	/**
	 * <P> Specifies an expandable set of test suites available for executing.
	 * The main class for each test suite has to belong to a unique package.</P>
	 */
	public static final String[] testSuiteMainClasses = new String[] {
		"basicTypes.ExamplesBasicTypes",  			/** basic types test cases */
		"equivalence.ExamplesEquivalence",          /** equivalence test cases */
		"exceptions.ExamplesExceptions",            /** exceptions test cases */
		"inexactValues.ExamplesInexact",  		    /** inexact values test cases */
		"iSame.ExamplesISame",					    /** iSame test cases */
		"iterable.ExamplesIterables",				/** iterable test cases */
		"maps.ExamplesMaps",						/** maps test cases */
		"methods.ExamplesMethods",					/** methods test cases */
		"randomChoice.ExamplesRandomChoice",		/** random choice test cases */
		"rangeCheck.ExamplesRangeCheck",			/** range check test cases */
		"sets.ExamplesSets",						/** sets test cases */
		"traversals.ExamplesTraversals",            /** traversals test cases */
		"userTypes.ExamplesUserTypes"				/** user types test cases */
	};

	/**
	 * A function that extracts short name of the package for each of
	 * the classes specified in argument. It also associates the package
	 * name with the class name.
	 * 
	 * @param testSuiteMainClasses the set of class names.
	 */

	private static Map<String, String> getMapTestSuitePackage2MainClass(String[] testSuiteMainClasses) {

		Map<String, String> res = new HashMap<String, String>();

		/** iterate through all class names */
		for (String mainClass: testSuiteMainClasses) {

			/** split the path to the class */
			String[] path = mainClass.split("\\.");

			/** get the last element but one */
			String packageName = path[path.length - 2];

			/** store it in the resulting HashMap */
			res.put(packageName.toLowerCase(), mainClass);
		}
		return res;
	}

	/**
	 * <P> The main function performs the execution of test suites.</P>
	 * <P> If no arguments provided, all test suites defined in
	 * <CODE>{@link allRun.ExamplesAllRun#testSuiteMainClasses testSuiteMainClasses}</CODE>
	 * will be executed. Otherwise only classes from packages provided
	 * as arguments will be run.</P>
	 * 
	 * @param args the list of short names for packages containing test
	 * suites to be executed. The corresponding test suite main classes
	 * have to be defined in
	 *  <CODE>{@link allRun.ExamplesAllRun#testSuiteMainClasses testSuiteMainClasses}</CODE>.
	 * E.g. provide <CODE>"exceptions inexact"<CODE> as method arguments
	 * if you want to execute test suites
	 * <CODE>{@link exceptions.ExamplesExceptions ExamplesExceptions}</CODE>
	 * and
	 * <CODE>{@link inexactValues.ExamplesInexact ExamplesInexact}</CODE>.
	 * Make sure you also put main classes
	 * <CODE>"exceptions.ExamplesExceptions"<CODE> and
	 * <CODE>"inexactValues.ExamplesInexact"<CODE> into
	 * <CODE>{@link allRun.ExamplesAllRun#testSuiteMainClasses testSuiteMainClasses}</CODE>.
	 */
	public static void main(String[] args) {

		/** extract short name for each package */
		Map<String, String> mapTestSuitePackage2MainClass =
			getMapTestSuitePackage2MainClass(testSuiteMainClasses);

		/** define the scope of testing */
		Collection<String> packagesToTest = 
			args.length > 0? Arrays.asList(args):       /** add test cases from the command line */
				mapTestSuitePackage2MainClass.keySet(); /** or add everything available for testing */


			/** iterate through package names */
			for (String packageName: packagesToTest) {
				/** get test suite main class to be executed */
				String mainClass = mapTestSuitePackage2MainClass.get(packageName.toLowerCase());

				try {
					/** get the class */
					Class<?> clazz = Class.forName(mainClass);

					/** get the main(String[] args) method */
					Method mainMethod = clazz.getMethod("main", new Class[]{String[].class});

					/** specify empty arguments */
					Object[] arguments = new Object[]{new String[0]};

					/** invoke the main method */
					mainMethod.invoke(null, arguments);
				} catch (Exception e) {
					/** notify if something went wrong */
					System.out.println("Cannot invoke the class for the package: " + packageName);
					e.printStackTrace();
				}
			}
	}
}